home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Special 18
/
AMIGAplus Sonderheft 18 (1999)(ICP)(DE)[!].iso
/
PD
/
Anwendungen
/
FS1541-13
/
disk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1999-01-03
|
8KB
|
403 lines
/*
* FS1541 - basic disk interaction routines
*
* Copyright (C) 1996 - 1998 Michael Krause
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <string.h>
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <exec/ports.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include "disk.h"
#include "volume.h"
LONG numsofterrors = 0;
static struct MsgPort *diskport;
struct IOExtTD *diskreq;
BOOL autoscan = TRUE;
struct MsgPort *dpsender;
static UBYTE *diskimage;
static int diskscanned;
static BYTE sectab[683];
static int curblk = 357; /* Preloading starts at 18,0 = BAM */
static int devopen = 0;
ULONG chgcount;
static BOOL ignoreall, abortall;
struct IntuitionBase *IntuitionBase;
int wprotected=FALSE, hardwprot=FALSE;
static void cacheblock(ULONG n, BOOL write);
/* ErrorReq() return codes */
#define REQ_RETRY 1
#define REQ_IGNORE 2
#define REQ_IGNORE_ALL 3
#define REQ_ABORT_ALL 0
/*-------------------------------------------------------------------------*/
LONG InitDiskSS(STRPTR device, ULONG unit, ULONG flags)
{
LONG error = 0;
if((diskimage = AllocVec(D64_SIZE, MEMF_PUBLIC)))
{
if((diskport = CreateMsgPort()))
{
if((diskreq = CreateIORequest(diskport, sizeof(struct IOExtTD))))
{
if((devopen = (!OpenDevice(device,unit,(struct IORequest *)diskreq,flags))))
{
return(0);
} else error = ERROR_DEVICE_NOT_MOUNTED;
} else error = ERROR_NO_FREE_STORE;
} else error = ERROR_NO_FREE_STORE;
} else error = ERROR_NO_FREE_STORE;
QuitDiskSS();
return(error);
}
void QuitDiskSS(void)
{
if(devopen)
CloseDevice((struct IORequest*)diskreq);
if(diskreq)
DeleteIORequest(diskreq);
if(diskport)
DeleteMsgPort(diskport);
if(diskimage)
FreeVec(diskimage);
}
/*-------------------------------------------------------------------------*/
void ResetDisk(void)
{
diskscanned = !autoscan;
memset(sectab, SEC_NOT_LOADED, 683);
curblk = 357;
abortall = FALSE;
ignoreall = FALSE;
diskreq->iotd_Req.io_Command = TD_CHANGENUM;
diskreq->iotd_Req.io_Flags = IOF_QUICK;
DoIO((struct IORequest*)diskreq);
chgcount = diskreq->iotd_Req.io_Actual;
diskreq->iotd_Req.io_Command = ETD_CLEAR;
diskreq->iotd_Count = chgcount;
diskreq->iotd_Req.io_Flags = IOF_QUICK;
DoIO((struct IORequest*)diskreq);
diskreq->iotd_Req.io_Command = TD_PROTSTATUS;
diskreq->iotd_Req.io_Flags = IOF_QUICK;
DoIO((struct IORequest*)diskreq);
hardwprot = diskreq->iotd_Req.io_Actual;
}
/* Asynchronous disk preloader */
BOOL LoadDisk(void)
{
if(!diskscanned && curvolumenode && autoscan)
{
int readblk;
for(readblk=curblk;readblk<683;readblk++)
if(sectab[readblk] == SEC_NOT_LOADED)
break;
if(readblk == 683)
{
if(curblk == 0)
{
/* Loading finished - switch off motor. */
diskreq->iotd_Req.io_Command = TD_MOTOR;
diskreq->iotd_Req.io_Flags = 0;
diskreq->iotd_Req.io_Length = 0;
DoIO((struct IORequest*)diskreq);
diskscanned = TRUE;
return(TRUE);
}
else
curblk = 0;
return(FALSE);
}
curblk = readblk;
cacheblock(readblk, FALSE);
return(FALSE);
} else return(TRUE);
}
void MotorOff(void)
{
if(diskscanned && CheckIO((struct IORequest*)UDStimer))
{
diskreq->iotd_Req.io_Command = ETD_UPDATE;
diskreq->iotd_Req.io_Flags = 0;
DoIO((struct IORequest*)diskreq);
diskreq->iotd_Req.io_Command = TD_MOTOR;
diskreq->iotd_Req.io_Flags = 0;
diskreq->iotd_Req.io_Length = 0;
DoIO((struct IORequest*)diskreq);
}
}
/*-------------------------------------------------------------------------*/
static LONG ts2block(UBYTE t, UBYTE s)
{
if(t<1)
{
return(-1);
}
else if(t<=17)
{
if(s>21)
return(-1);
else
return(21*(t-1) + s);
}
else if(t<=24)
{
if(s>19)
return(-1);
else
return(21*17 + 19*(t-18) + s);
}
else if(t<=30)
{
if(s>18)
return(-1);
else
return(21*17 + 19*7 + 18*(t-25) + s);
}
else if(t<=35)
{
if(s>17)
return(-1);
else
return(21*17 + 19*7 + 18*6 + 17*(t-31) + s);
}
else
return(-1);
}
int
SectorsOnTrack (BYTE track)
{
if(track < 1)
return 0;
if(track < 18)
return 21;
if(track < 25)
return 19;
if(track < 31)
return 18;
if(track < 36)
return 17;
return 0;
}
UWORD
Block2TS (UWORD blk)
{
UWORD t,s,i,b=0;
for (t=1;t<36;t++)
{
i=SectorsOnTrack(t);
for (s=0;s<i;s++)
{
if (b==blk) return ((t<<8)|s);
b++;
}
}
return (0);
}
struct DataBlock *getblock_ts(UBYTE t, UBYTE s)
{
LONG blk = ts2block(t, s);
if(blk>=0)
return(getputblock(blk, FALSE));
else
return(NULL);
}
struct DataBlock *putblock_ts(UBYTE t, UBYTE s, APTR data)
{
LONG blk = ts2block(t, s);
if(blk>=0)
{
CopyMem(data, diskimage+(blk*256), 256);
return(getputblock(blk, TRUE));
}
else
return(NULL);
}
static int
ErrorReq (ULONG blk)
{
static struct EasyStruct req = {
sizeof(struct EasyStruct),
0,
"FS1541 Error",
"Volume %s has a\nread/write error on\ntrack %ld, sector %ld.",
"Retry|Ignore|Ignore All|Abort All" /* see REQ_ defines at the top of the file */
};
struct Process *pr = dpsender->mp_SigTask;
int x;
if(!curvolumenode)
return -1;
if(abortall)
return REQ_ABORT_ALL;
if(ignoreall)
return REQ_IGNORE_ALL;
if(!(IntuitionBase = (struct IntuitionBase*)OpenLibrary("intuition.library",36)))
return -1;
if((dpsender->mp_Flags & PF_ACTION) != PA_SIGNAL
|| pr->pr_Task.tc_Node.ln_Type != NT_PROCESS
|| pr->pr_WindowPtr != (APTR)-1) {
UWORD ts = Block2TS(blk);
ULONG args[3] = {
(ULONG)&curvolumenode->name[1],
(ULONG)(ts>>8),
(ULONG)(ts&0xFF)
};
x = EasyRequestArgs(NULL, &req, NULL, args);
} else {
x = REQ_ABORT_ALL;
}
CloseLibrary((struct Library*)IntuitionBase);
return x;
}
struct DataBlock *
getputblock (ULONG blk,
BOOL write)
{
int retry;
int num = REQ_IGNORE;
if(blk >= 683)
return NULL;
if(write)
cacheblock(blk, TRUE);
switch(sectab[blk]) {
case SEC_NOT_LOADED:
do {
retry = 10;
while (retry) {
curblk = blk;
cacheblock(blk, FALSE);
if(sectab[blk] == SEC_OK)
return (struct DataBlock*)(diskimage+(blk*256));
retry--;
}
} while((num = ErrorReq(blk)) == REQ_RETRY);
/* fall through */
case SEC_ERROR:
default:
switch(num) {
case REQ_IGNORE_ALL:
ignoreall = TRUE;
/* fall through */
case REQ_IGNORE:
return (struct DataBlock*)(diskimage+(blk*256));
case REQ_ABORT_ALL:
default:
abortall = TRUE;
return NULL;
}
return NULL;
case SEC_OK:
return (struct DataBlock*)(diskimage+(blk*256));
}
}
static void
cacheblock (ULONG n,
BOOL write)
{
diskreq->iotd_Count = chgcount;
diskreq->iotd_Req.io_Command = write ? ETD_WRITE : ETD_READ;
diskreq->iotd_Req.io_Flags = 0;
diskreq->iotd_Req.io_Data = diskimage+(n*256);
diskreq->iotd_Req.io_Offset = 256*n;
diskreq->iotd_Req.io_Length = 256;
if(!DoIO((struct IORequest*)diskreq)) {
sectab[n] = SEC_OK;
} else {
sectab[n] = SEC_ERROR;
numsofterrors++;
if(!curvolumenode) {
/* Switch off the motor, unread/writable disk. */
diskreq->iotd_Req.io_Command = TD_MOTOR;
diskreq->iotd_Req.io_Flags = 0;
diskreq->iotd_Req.io_Length = 0;
DoIO((struct IORequest*)diskreq);
}
}
}